package testApplets;



import simpleGeom.Box3D;
import simpleGeom.Grid3DFloat;
import simpleGeom.MMesh;
import simpleGeom.SimpleMCube;

import processing.core.PApplet;

public class VoxelizeBasic extends PApplet {
	
	MMesh mesh;
	Box3D bounds;	
	SimpleMCube mc=new SimpleMCube();
	Grid3DFloat grid;
	float iso;
	String objectInputPath="/Users/administrator/Desktop/sketch_Voxelize/data/test.obj";
	String objectOutputPath="/Users/administrator/Desktop/sketch_Voxelize/data/output.obj";
	// two steps: 
	// 1. scan the geometry, calculate a distance field
	// 2. do marching cube
	
	public void setup() {
		// import mesh
		mesh = new MMesh();
		mesh.loadOBJ(objectInputPath);
		mesh.triangulateQuads();
		scan(200);
		defineInsideOutside();
		// parameters:
		// int 		nX, nY, nZ: dimensions of the voxelgrid
		// float[] 	the array with the isovalues
		// float 	isovalue (should be >=dim*0.8f)
		// float 	scale
		// float 	x,y,z: translation
		// String 	(optional path for saving the .obj directly, this saves memory) 
		mc.marchingCubes(grid.nX, grid.nY, grid.nZ, grid.values, iso, grid.dim, grid.x1, grid.y1,
				grid.z1, objectOutputPath);
	}
	
	
	public void scan(int resolution){
		bounds=mesh.getBounds();
		float dim = bounds.getDimX() / resolution;
		iso=dim*0.85f;
		bounds=bounds.getOffsetBox(dim*2);
		float dimX = bounds.getDimX() ;
		float dimY = bounds.getDimY() ;
		float dimZ = bounds.getDimZ() ;
		dim = dimX / resolution;
		int nX = (int) (dimX / dim) + 2;
		int nY = (int) (dimY / dim) + 2;
		int nZ = (int) (dimZ / dim) + 2;
		
		grid=new Grid3DFloat(nX,nY,nZ);
		grid.x1=bounds.x1;
		grid.y1=bounds.y1;
		grid.z1=bounds.z1;
		grid.dim=dim;
		
		// scanning
		// float[] 	xcoordinates
		// float[] 	ycoordinates
		// float[] 	zcoordinates
		// int[] 	triangleindex 
		// float 	x,y,z: lowerleft corner of the scanvolume
		// int 		nx,ny,nz: dimensions of the voxelgrid
		// float 	dimension of the voxelgrid
		// float 	maximal distance that will be evaluated. all voxels that are more far away will have a very high distancce
		// 			this reduces calculation time, as not every voxel value needs to be calculated.
		MMesh.scanMeshDistance(mesh.xc, mesh.yc, mesh.zc, mesh.triangles,
				bounds.x1, bounds.y1, bounds.z1, nX, nY, nZ, dim, dim * 1.5f,
				grid.values);
	}
	
	public void defineInsideOutside() {
		float iso=2;
		int[] boxInside=new int[6];	//x1,y1,z1,x2,y2,z2
		boxInside[3]=grid.nX;
		boxInside[4]=grid.nY;
		boxInside[5]=grid.nZ;
		println("start reach");
		int index=grid.getIndex(0, 0,0);
		Grid3DFloat.reached(grid.values, grid.nX, grid.nY, grid.nZ, index,iso);
		println("end reach");
		
		for (int i = 0; i < grid.values.length; i++) {
			if (grid.values[i] < 0) 
				grid.values[i] *= -1; // smaller 0 means reached
			 else if (grid.values[i] > iso) 
				 grid.values[i] = 0; // bigger iso 
		}
		
		// define borders
		for (int x = 0; x < grid.nX; x++) {
			for (int y = 0; y < grid.nY; y++) {
				for (int z = 0; z < grid.nZ; z++) {
					if (boxInside[0] > x || boxInside[3] < x
							|| boxInside[1] > y || boxInside[4] < y
							|| boxInside[2] > z || boxInside[5] < z) {
						grid.values[x * grid.nY * grid.nZ + y * grid.nZ + z] = grid.dim * 2;
					}
				}
			}
		}
	}
}
